﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace DiagramDesigner
{
    public class AngleLine : PointLine
    {
        public AngleLine()
            : base()
        {
            
        }

        static AngleLine()
        {
            PointLine.StartPointProperty.OverrideMetadata(typeof(AngleLine),
                new FrameworkPropertyMetadata(new Point(0, 0), null, CoerceStartPointChangeCallback));
        }



        public LineModel Baseline
        {
            get { return (LineModel)GetValue(BaselineProperty); }
            set { SetValue(BaselineProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Baseline.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty BaselineProperty =
            DependencyProperty.Register("Baseline", typeof(LineModel), typeof(AngleLine),
            new UIPropertyMetadata(null, BaseLineChangedCallback));

        private static void BaseLineChangedCallback(DependencyObject obj,
           DependencyPropertyChangedEventArgs e)
        {
            AngleLine _this = (AngleLine)obj;
            LineModel bl = e.NewValue as LineModel;
            LineModel blo = e.OldValue as LineModel;

            if (blo != null)
            {
                blo.PropertyChanged -= new PropertyChangedEventHandler(_this.bl_PropertyChanged);
            }
            if (bl != null)
            {
                bl.PropertyChanged += new PropertyChangedEventHandler(_this.bl_PropertyChanged);
            }

            _this.StartPoint = _this.AdjustStart(_this.StartPoint);
        }

        void bl_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == LineModel.Pt1PropertyName || e.PropertyName == LineModel.Pt2PropertyName)
            {
                StartPoint = AdjustStart(StartPoint);
            }
        }

        private void BaseLinePointChanged(object sender, EventArgs e)
        {
            StartPoint = AdjustStart(StartPoint);
        }
        

        //// Using a DependencyProperty as the backing store for BaseLine.  This enables animation, styling, binding, etc...
        //public static readonly DependencyProperty BaseLineProperty =
        //    DependencyProperty.Register("BaseLine", typeof(PointLine), typeof(AngleLine),
        //    new UIPropertyMetadata(null, BaseLineChangedCallback));

        //public PointLine BaseLine
        //{
        //    get { return (PointLine)GetValue(BaseLineProperty); }
        //    set { SetValue(BaseLineProperty, value); }
        //}

        //private static void BaseLineChangedCallback(DependencyObject obj,
        //   DependencyPropertyChangedEventArgs e)
        //{
        //    AngleLine _this = (AngleLine)obj;
        //    PointLine bl = e.NewValue as PointLine;
        //    PointLine blo = e.OldValue as PointLine;

        //    DependencyPropertyDescriptor propS = DependencyPropertyDescriptor.FromProperty(
        //        PointLine.StartPointProperty, typeof(PointLine));

        //    DependencyPropertyDescriptor propE = DependencyPropertyDescriptor.FromProperty(
        //        PointLine.EndPointProperty, typeof(PointLine));

        //    if (blo != null)
        //    {
        //        propS.RemoveValueChanged(blo, new EventHandler(_this.BaseLinePointChanged));
        //        propE.RemoveValueChanged(blo, new EventHandler(_this.BaseLinePointChanged));
        //    }
        //    if (bl != null)
        //    {
        //        propS.AddValueChanged(bl, new EventHandler(_this.BaseLinePointChanged));
        //        propE.AddValueChanged(bl, new EventHandler(_this.BaseLinePointChanged));
        //    }

        //    _this.StartPoint = _this.AdjustStart(_this.StartPoint);
        //}

        //private void BaseLinePointChanged(object sender, EventArgs e)
        //{
        //    StartPoint = AdjustStart(StartPoint);
        //}
        

        private Point AdjustStart(Point p)
        {
            Point p1 = Baseline.Pt1;
            Point p2 = Baseline.Pt2;

            //find StartPoint projection onto the substrate
            double fDenominator = (p2.X - p1.X) * (p2.X - p1.X) + (p2.Y - p1.Y) * (p2.Y - p1.Y);

            if (fDenominator == 0) // p1 and p2 are the same
                return p1;

            double t = (p.X * (p2.X - p1.X) - (p2.X - p1.X) * p1.X + p.Y * (p2.Y - p1.Y) - (p2.Y - p1.Y) * p1.Y) / fDenominator;
            if (t < 0)
                t = 0;
            if (t > 1)
                t = 1;

            return new Point(p1.X + (p2.X - p1.X) * t, p1.Y + (p2.Y - p1.Y) * t);
        }

        private static object CoerceStartPointChangeCallback(DependencyObject obj,
           object val)
         {
             AngleLine _this = (AngleLine)obj;
             Point p = (Point) val;

             if (_this.Baseline == null)
                 return p;
             
            return _this.AdjustStart(p);             

         }
    
        
    }    
}
